docs: validate state.returnTo before navigating#99
Conversation
The "Passing Data Through Auth Flows" example showed `window.location.href = state.returnTo` with no validation. Since `state` round-trips through the redirect as plaintext in the URL and is not validated by WorkOS, an unvalidated `returnTo` is an open-redirect / `javascript:`-URI sink. Replace the example with an origin-resolve + same-origin check and add a warning that `state` contents are untrusted.
Greptile SummaryThis PR fixes an open redirect (and potential XSS) vulnerability in the README documentation example by replacing unvalidated
Confidence Score: 5/5Safe to merge. The change is documentation-only and replaces a vulnerable pattern with a well-structured same-origin validation that correctly handles all known bypass vectors. The PR removes a documented open-redirect/XSS pattern and replaces it with a robust origin-checked navigation example. The try-catch handles malformed URLs, the origin equality check blocks absolute and protocol-relative URLs, and navigating via url.href (not a reconstructed path) sidesteps the pathname reassembly bypass. No runtime code is changed — only README documentation. No files require special attention. The only changed file is README.md. Important Files Changed
|
Building on the try/catch guard: reconstructing from url.pathname can yield a protocol-relative path (e.g. returnTo "https://your-app//evil.com" → pathname "//evil.com") that redirects off-site even though the origin check passed. Navigating to the origin-validated url.href avoids this.
What
Updates the "Passing Data Through Auth Flows" README example. The previous example navigated directly to a value read from
state:Replaced with an origin-resolve + same-origin check, plus a
[!WARNING]callout thatstateis untrusted input.Why
stateround-trips through the OAuth redirect as plaintext in the URL and is not validated by WorkOS. Copying the documented example verbatim and populatingreturnTofrom request-derived data yields an open redirect — or XSS, sincewindow.location.href = 'javascript:...'executes. The docs are de-facto the happy path here, so the example itself was teaching the vulnerable pattern.The replacement resolves
returnToagainstwindow.location.originand only navigates if it stays same-origin, which rejects absolute URLs, protocol-relative//evil.com, andjavascript:URIs in one step — no fragile string matching.🤖 Generated with Claude Code